/** @file gui_scrollbar.h
    @brief Scrollbar widget */

#ifndef G3_SCROLLBAR_H
#define G3_SCROLLBAR_H

#include "gui/gui_widget.h"

namespace G3 {
namespace GUI {

/** Minimum Scrolling bar length - 3 pixels by default */
extern int MinimumScrollingBarLength;
/** Minimum Scrolling bar button size - 3 pixels by default */
extern int MinimumScrollBarButtonSize;

/** @class SCROLLBAR
    @brief A scrollbar widget class */
class SCROLLBAR: public WIDGET {
    public:
        /**
            @brief Guess what, a constructor..
        */
        SCROLLBAR ();

        //! \todo Figure out, what dis does
        bool ScrollToUpmostLine;

        /** Make sure that when scrolling, the upmost line in the window is kept in the position (Ugh, hrd 2 xplain) */
        bool KeepUpmostLine;

        /** Bar socket color */
        G3::COL4F BgColor;
        /** Bar and arrows color */
        G3::COL4F FgColor;

        /** Number of scrollable lines in total */
        int TotalSize;
        /** Number of lines in the scrollable window */
        int VisibleSize;
        /** Active line */
        int CurrentLine;

        /** Is mouse chewing the scrollingbar ? */
        bool MouseChews;
        /** Is the user dragging the scrollingbar ? */
        bool DraggingBar;

        /** Last mouse position */
        G3::VEC2D LastMousePosition;

        /** The dimensions of up / down buttons */
        G3::VEC2D ButtonDimensions;

        /** Length of the scrollingbar */
        float BarLength;
        /** Scrollingbar distance from the start corner (up or left - depends on the dimensions aspect ratio)  */
        float BarPosition;
        /** Length of the scrollingbar socket */
        float BarSocketHeight;

        /** Mouse wheel sensitivity */
		float WheelSensitivity;

        /** Signal for the Mouse-Move event */
		SIG_NOTIFY_EVENT SigMouseMove;
        /** Signal for the Change event */
		SIG_NOTIFY_EVENT SigChange;

        /** Connection for the Mouse-Move event */
        vector<SIG_CONNECTION> ConnMouseMove;
        /** Connection for the Change event */
        vector<SIG_CONNECTION> ConnChange;

        /**
            @brief Sets the Mouse-Move event handler callback function pointer
            @param[in] aNotifyHandler Pointer to the Mouse-Move event handler callback function
            @return The freshly produced connection
        */
        SIG_CONNECTION doOnMouseMove (NOTIFY_HANDLER aNotifyHandler);
        /**
            @brief Sets the Change event handler callback function pointer
            @param[in] aNotifyHandler Pointer to the Change event handler callback function
            @note Change event handlers don't receive Input pointers - the Input argument is NULL.
            @return The freshly produced connection
        */
        SIG_CONNECTION doOnChange (NOTIFY_HANDLER aNotifyHandler);

        /** Sets whole scrollbar dimensions */
        void SetDimensions (int w, int h);
        /** Sets scrollbar button dimensions */
        void SetButtonDimensions (int w, int h);

        /**
            @brief Sets total window size, visible window size and currently selected line attributes
            @param[in] TotalWindowSize Number of lines in the scrollable window
            @param[in] VisibleWindowSize Number of lines visible in the window
            @param[in] CurrentViewPosition Currently active line number
        */
        void SetAttribs (int TotalWindowSize, int VisibleWindowSize, int CurrentViewPosition);

        void SetViewPosition (int CurrentViewPosition);
        int GetViewPosition ();

        /**
            @brief Returns the bar rectangle
            @return The rectangle
        */
        G3::RECTI GetBarRect ();

        /**
            @brief Returns the previous button (up / left) rectangle
            @return The rectangle
        */
        G3::RECTI GetPrevButtonRect ();

        /**
            @brief Returns the next button (down / right) rectangle
            @return The rectangle
        */
        G3::RECTI GetNextButtonRect ();

        /**
            @brief Returns the bar socket rectangle
            @return The rectangle
        */
        G3::RECTI GetBarSocketRect ();

        /**
            @brief Checks if the scrollbar is vertical
            @return True if it is, otherwise false
        */
        inline bool IsVertical () const { return Rect.IsVertical (); }
        /**
            @brief Sets the scrollbar vertical
        */
        void SetVertical ();
        /**
            @brief Sets the scrollbar horizontal
        */
        void SetHorizontal ();

        /**
            @brief Triggers a MouseDown on the scrollbar
            @param[in] MouseX Mouse X-coordinate
            @param[in] MouseY Mouse Y-coordinate
        */
        void Clicked (int MouseX, int MouseY);

        /**
            @brief Updates mouse position
            @param[in] MouseX Mouse X-coordinate
            @param[in] MouseY Mouse Y-coordinate
        */
        void SetMousePosition (int MouseX, int MouseY);

        /**
            @brief Updates mouse wheel position
            @param[in] MouseZ Mouse Z-coordinate
        */
		void SetWheelPosition (int MouseZ);

        /**
            @brief Updates the bar position
            @param[in] DeltaX Bar delta X-coordinate
            @param[in] DeltaY Bar delta Y-coordinate
        */
        void UpdateBarPosition (int DeltaX, int DeltaY);

        /**
            @brief Triggers a MouseUp on the scrollbar
        */
        void UnClicked ();

        /**
            @brief Gets the type of the widget
            @return the type index. \see TYPE_MANAGER
        */
		virtual uint GetType () { return MainTypeMgr.GetType ("W_SCROLLBAR"); }

        /**
            @brief Is the widget static ?
            @return A scrollbar isn't
        */
		virtual bool IsStatic () { return false; }

        /**
            @brief Renders the scrollbar
            @param[in] aElapsedTime Elapsed time since the last call
        */
        virtual void Draw (float aElapsedTime = 0.0f);

    private:

        /**
            @brief Calculates the scrolling bar length
        */
        void CalculateBar ();

        /**
            @brief Calculates the view position
        */
        void CalculateViewPosition ();
};

/**
    @brief Scrollbar MouseMove event handler
    @param[in] Input Pointer to the input class
    @param[out] Widget Pointer to the scrollbar
*/
void ScrollbarMouseMove (G3::INPUT *Input, G3::GUI::WIDGET *Widget);

/**
    @brief Scrollbar MouseDown event handler
    @param[in] Input Pointer to the input class
    @param[out] Widget Pointer to the scrollbar
*/
void ScrollbarMouseDown (G3::INPUT *Input, G3::GUI::WIDGET *Widget);

/**
    @brief Scrollbar MouseUp event handler
    @param[in] Input Pointer to the input class
    @param[out] Widget Pointer to the scrollbar
*/
void ScrollbarMouseUp (G3::INPUT *Input, G3::GUI::WIDGET *Widget);

}
}

#endif // G3_SCROLLBAR_H
